{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Docker部署模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 拉取 Docker 镜像"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    ">>> docker pull tensorflow/serving\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 在运行的容器内运行 ModelServer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    ">>> tensorflow_model_server --port=8500 --rest_api_port=8501 \\\n",
    "  --model_name=${MODEL_NAME} --model_base_path=${MODEL_BASE_PATH}/${MODEL_NAME}\n",
    "```\n",
    "- `gRPC` 端口为 8500\n",
    "- `REST API` 端口为 8501\n",
    "- 环境变量 `MODEL_NAME`，默认值为 `model`，标识模型的名称\n",
    "- 环境变量 `MODEL_BASE_PATH`，默认值 `/models`，标识模型文件存放的路径"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过docker运行ModelServer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    ">>> docker run -p 8501:8501 \\\n",
    "  --mount type=bind,source=/path/to/my_model/,target=/models/my_model \\\n",
    "  -e MODEL_NAME=my_model -t tensorflow/serving\n",
    "```\n",
    "- `-p 8501:8501` \n",
    "    - 将容器的 8501 端口绑定到宿主机的 8501 端口\n",
    "- `--mount type=bind,source=/path/to/my_model/,target=/models/my_model` \n",
    "    - 将存放在本地目录`source=/path/to/my_model/`中的名为 `my_model` 的模型，挂载到容器的的路径上`target=/models/my_model`\n",
    "    \n",
    "----    \n",
    "    \n",
    "    \n",
    "运行该命令，会启动 `serving` 的容器，并在容器内部运行:\n",
    "```shell\n",
    "    >>> tensorflow_model_server --port=8500 --rest_api_port=8501 \\\n",
    "       --model_name=my_model --model_base_path=/models/my_model\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 其它参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`tensorflow_model_server` 支持其它一些参数，例如提供模型配置文件，而不是模型名称：\n",
    "```shell\n",
    ">>> docker run -p 8500:8500 -p 8501:8501 \\\n",
    "  --mount type=bind,source=/path/to/my_model/,target=/models/my_model \\\n",
    "  --mount type=bind,source=/path/to/my/models.config,target=/models/models.config \\\n",
    "  -t tensorflow/serving --model_config_file=/models/models.config\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    "# 查看正在运行的容器\n",
    "hahaha@carpediem:~$ docker container ls\n",
    "CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              \n",
    "9986cca3b23d        tensorflow/serving   \"/usr/bin/tf_serving…\"   35 minutes ago      Up 35 minutes       \n",
    "\n",
    "# 指定容器ID，进入容器内，执行 bash 命令\n",
    "hahaha@carpediem:~$ docker exec -it 9986cca3b23d /bin/bash\n",
    "\n",
    "# 在容器内查看 tensorflow_model_server 命令\n",
    "root@9986cca3b23d:/# tensorflow_model_server --help\n",
    "usage: tensorflow_model_server\n",
    "Flags:\n",
    "\t--port=8500                      \tint32\tPort to listen on for gRPC API\n",
    "\t--grpc_socket_path=\"\"            \tstring\tIf non-empty, listen to a UNIX socket for gRPC API on the \n",
    "\t--rest_api_port=0                \tint32\tPort to listen on for HTTP/REST API. If set to zero HTTP/REST \n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 将模型封装成 docker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 启动镜像，作为守护进程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    ">>> docker run -d --name serving_base tensorflow/serving\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 将保存的模型复制到容器内"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    ">>> docker cp models/<my model> serving_base:/models/<my model>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 重命名封装的模型容器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```shell\n",
    ">>> docker commit --change \"ENV MODEL_NAME <my model>\" serving_base <my container>\n",
    "```\n",
    "\n",
    "停止守护进程容器 `>>> docker kill serving_base`，剩下的名为 `<my container>` 的容器即为封装的模型容器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 保存模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 保存通过 keras 训练得到的模型 `model`，需要指定输入输出参数`inputs, outputs`\n",
    "\n",
    "```python\n",
    "tf.saved_model.simple_save(\n",
    "    keras.backend.get_session(),\n",
    "    directory_path,\n",
    "    inputs={\"input_image\": model.input},\n",
    "    outputs={i.name: i for i in model.outputs},\n",
    ")\n",
    "```\n",
    "-----------------------\n",
    "- 查看模型文件夹内容，模型被保存为 `.pb` 文件：\n",
    "     \n",
    "```\n",
    "hahah7@carpediem:/path/to/my_model$ tree\n",
    ".\n",
    "├── assets\n",
    "│   └── foo.txt\n",
    "├── saved_model.pb\n",
    "└── variables\n",
    "    ├── variables.data-00000-of-00001\n",
    "    └── variables.index\n",
    "\n",
    "2 directories, 4 files\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "- 查看模型内部信息：\n",
    "\n",
    "```shell\n",
    "hahah7@carpediem:/path/to/my_model$ saved_model_cli show --dir . --al\n",
    "MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:\n",
    "\n",
    "signature_def['classify_x_to_y']:\n",
    "  The given SavedModel SignatureDef contains the following input(s):\n",
    "    inputs['inputs'] tensor_info:\n",
    "        dtype: DT_STRING\n",
    "        shape: unknown_rank\n",
    "        name: tf_example:0\n",
    "  The given SavedModel SignatureDef contains the following output(s):\n",
    "    outputs['scores'] tensor_info:\n",
    "        dtype: DT_FLOAT\n",
    "        shape: (-1, 1)\n",
    "        name: y:0\n",
    "  Method name is: tensorflow/serving/classify\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 调用模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "命令行：\n",
    "```\n",
    ">>> curl -d '{\"instances\": [1.0, 2.0, 5.0]}' -X POST http://localhost:8501/v1/models/half_plus_two:predict\n",
    "```            \n",
    "- POST 的数据必须满足 `tf.saved_model` 时的格式：`inputs={\"instances\": model.input}   --> {\"instances\": [1.0, 2.0, 5.0]}`\n",
    "- URL 为 `http://localhost:8501/v1/models/<model_name>:predict`，其中 `<model_name>` 为启动镜像时的模型名称"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "python:\n",
    "```python\n",
    "x = np.array([1.0, 2, 3])\n",
    "data = json.dump({\"instances\": x})\n",
    "res = requests.post(\"http://localhost:8501/v1/models/half_plus_two:predict\",\n",
    "                    data=data)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 示例"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建模型 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:35:58.392464Z",
     "start_time": "2020-06-13T10:35:57.506815Z"
    }
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:35:59.292370Z",
     "start_time": "2020-06-13T10:35:59.254134Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "No GPU found\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU'),\n",
       " PhysicalDevice(name='/physical_device:XLA_CPU:0', device_type='XLA_CPU')]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "os.environ['CUDA_VISIBLE_DEVICES'] = '-1'\n",
    "\n",
    "if tf.test.gpu_device_name():\n",
    "    print('GPU found')\n",
    "else:\n",
    "    print(\"No GPU found\")\n",
    "\n",
    "my_devices = tf.config.experimental.list_physical_devices()\n",
    "my_devices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:00.260463Z",
     "start_time": "2020-06-13T10:36:00.066601Z"
    }
   },
   "outputs": [],
   "source": [
    "(X_train_full, y_train_full), (X_test,\n",
    "                               y_test) = tf.keras.datasets.mnist.load_data()\n",
    "X_train_full = X_train_full[..., np.newaxis].astype(np.float32) / 255.\n",
    "X_test = X_test[..., np.newaxis].astype(np.float32) / 255.\n",
    "\n",
    "X_valid, X_train = X_train_full[:5000], X_train_full[5000:]\n",
    "y_valid, y_train = y_train_full[:5000], y_train_full[5000:]\n",
    "X_new = X_test[:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:01.197869Z",
     "start_time": "2020-06-13T10:36:01.195631Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((55000, 28, 28, 1), (5000, 28, 28, 1), (5000,))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train.shape, X_valid.shape, y_valid.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:12.321691Z",
     "start_time": "2020-06-13T10:36:02.826392Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "1719/1719 [==============================] - 1s 577us/step - loss: 0.7012 - accuracy: 0.8241 - val_loss: 0.3715 - val_accuracy: 0.9024\n",
      "Epoch 2/10\n",
      "1719/1719 [==============================] - 1s 517us/step - loss: 0.3536 - accuracy: 0.9020 - val_loss: 0.2990 - val_accuracy: 0.9144\n",
      "Epoch 3/10\n",
      "1719/1719 [==============================] - 1s 527us/step - loss: 0.3036 - accuracy: 0.9145 - val_loss: 0.2651 - val_accuracy: 0.9272\n",
      "Epoch 4/10\n",
      "1719/1719 [==============================] - 1s 536us/step - loss: 0.2736 - accuracy: 0.9231 - val_loss: 0.2436 - val_accuracy: 0.9334\n",
      "Epoch 5/10\n",
      "1719/1719 [==============================] - 1s 524us/step - loss: 0.2509 - accuracy: 0.9296 - val_loss: 0.2257 - val_accuracy: 0.9364\n",
      "Epoch 6/10\n",
      "1719/1719 [==============================] - 1s 524us/step - loss: 0.2322 - accuracy: 0.9350 - val_loss: 0.2121 - val_accuracy: 0.9396\n",
      "Epoch 7/10\n",
      "1719/1719 [==============================] - 1s 536us/step - loss: 0.2161 - accuracy: 0.9400 - val_loss: 0.1970 - val_accuracy: 0.9454\n",
      "Epoch 8/10\n",
      "1719/1719 [==============================] - 1s 555us/step - loss: 0.2021 - accuracy: 0.9432 - val_loss: 0.1880 - val_accuracy: 0.9476\n",
      "Epoch 9/10\n",
      "1719/1719 [==============================] - 1s 520us/step - loss: 0.1898 - accuracy: 0.9470 - val_loss: 0.1778 - val_accuracy: 0.9524\n",
      "Epoch 10/10\n",
      "1719/1719 [==============================] - 1s 530us/step - loss: 0.1793 - accuracy: 0.9493 - val_loss: 0.1685 - val_accuracy: 0.9546\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x7f15380fb910>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.seed(10)\n",
    "tf.random.set_seed(42)\n",
    "\n",
    "model = tf.keras.models.Sequential([\n",
    "    tf.keras.layers.Flatten(input_shape=[28, 28, 1]),\n",
    "    tf.keras.layers.Dense(100, activation=\"relu\"),\n",
    "    tf.keras.layers.Dense(10, activation='softmax')\n",
    "])\n",
    "\n",
    "model.compile(loss=\"sparse_categorical_crossentropy\",\n",
    "              optimizer=tf.keras.optimizers.SGD(lr=1e-2),\n",
    "              metrics=[\"accuracy\"])\n",
    "model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:16.313963Z",
     "start_time": "2020-06-13T10:36:16.246257Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 1.  , 0.  , 0.  ],\n",
       "       [0.  , 0.  , 0.99, 0.01, 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ],\n",
       "       [0.  , 0.97, 0.01, 0.  , 0.  , 0.  , 0.  , 0.01, 0.  , 0.  ]],\n",
       "      dtype=float32)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.round(model.predict(X_new), 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:17.987615Z",
     "start_time": "2020-06-13T10:36:17.981828Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'../../H/models/my_mnist_model/0001'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "model_version = \"0001\"\n",
    "model_name = \"../../H/models/my_mnist_model\"\n",
    "model_path = os.path.join(model_name, model_version)\n",
    "model_path"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 本地模型文件详情"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:19.841154Z",
     "start_time": "2020-06-13T10:36:19.720913Z"
    }
   },
   "outputs": [],
   "source": [
    "!rm -rf model_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:23.210079Z",
     "start_time": "2020-06-13T10:36:23.001896Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /home/yangbin7/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "INFO:tensorflow:Assets written to: ../../H/models/my_mnist_model/0001/assets\n"
     ]
    }
   ],
   "source": [
    "# 保存模型\n",
    "tf.saved_model.save(model, model_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:30.070407Z",
     "start_time": "2020-06-13T10:36:30.064371Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                my_mnist_model/\n",
      "                    0001/\n",
      "                        saved_model.pb\n",
      "                        assets/\n",
      "                        variables/\n",
      "                            variables.data-00001-of-00002\n",
      "                            variables.data-00000-of-00001\n",
      "                            variables.index\n",
      "                            variables.data-00000-of-00002\n"
     ]
    }
   ],
   "source": [
    "# 模型文件\n",
    "for root, dirs, files in os.walk(model_name):\n",
    "    indent = '    ' * root.count(os.sep)\n",
    "    print('{}{}/'.format(indent, os.path.basename(root)))\n",
    "    for filename in files:\n",
    "        print('{}{}'.format(indent + '    ', filename))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:33.066765Z",
     "start_time": "2020-06-13T10:36:31.835722Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The given SavedModel contains the following tag-sets:\r\n",
      "'serve'\r\n"
     ]
    }
   ],
   "source": [
    "# 显示模型详情\n",
    "!saved_model_cli show --dir {model_path}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:35.595059Z",
     "start_time": "2020-06-13T10:36:34.365443Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:\r\n",
      "SignatureDef key: \"__saved_model_init_op\"\r\n",
      "SignatureDef key: \"serving_default\"\r\n"
     ]
    }
   ],
   "source": [
    "!saved_model_cli show --dir {model_path} --tag_set serve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:37.949922Z",
     "start_time": "2020-06-13T10:36:36.721880Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The given SavedModel SignatureDef contains the following input(s):\r\n",
      "  inputs['flatten_input'] tensor_info:\r\n",
      "      dtype: DT_FLOAT\r\n",
      "      shape: (-1, 28, 28, 1)\r\n",
      "      name: serving_default_flatten_input:0\r\n",
      "The given SavedModel SignatureDef contains the following output(s):\r\n",
      "  outputs['dense_1'] tensor_info:\r\n",
      "      dtype: DT_FLOAT\r\n",
      "      shape: (-1, 10)\r\n",
      "      name: StatefulPartitionedCall:0\r\n",
      "Method name is: tensorflow/serving/predict\r\n"
     ]
    }
   ],
   "source": [
    "!saved_model_cli show --dir {model_path} --tag_set serve --signature_def serving_default"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:36:40.899547Z",
     "start_time": "2020-06-13T10:36:39.588431Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:\n",
      "\n",
      "signature_def['__saved_model_init_op']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['__saved_model_init_op'] tensor_info:\n",
      "        dtype: DT_INVALID\n",
      "        shape: unknown_rank\n",
      "        name: NoOp\n",
      "  Method name is: \n",
      "\n",
      "signature_def['serving_default']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "    inputs['flatten_input'] tensor_info:\n",
      "        dtype: DT_FLOAT\n",
      "        shape: (-1, 28, 28, 1)\n",
      "        name: serving_default_flatten_input:0\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['dense_1'] tensor_info:\n",
      "        dtype: DT_FLOAT\n",
      "        shape: (-1, 10)\n",
      "        name: StatefulPartitionedCall:0\n",
      "  Method name is: tensorflow/serving/predict\n",
      "WARNING:tensorflow:From /home/yangbin7/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "\n",
      "Defined Functions:\n",
      "  Function Name: '__call__'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #2\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          flatten_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='flatten_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #3\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #4\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          flatten_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='flatten_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "\n",
      "  Function Name: '_default_save_signature'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          flatten_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='flatten_input')\n",
      "\n",
      "  Function Name: 'call_and_return_all_conditional_losses'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #2\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          flatten_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='flatten_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #3\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          flatten_input: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='flatten_input')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n",
      "    Option #4\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float32, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "        Argument #3\n",
      "          DType: NoneType\n",
      "          Value: None\n"
     ]
    }
   ],
   "source": [
    "!saved_model_cli show --dir {model_path} --all"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 调用模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:37:26.393762Z",
     "start_time": "2020-06-13T10:37:26.391537Z"
    }
   },
   "outputs": [],
   "source": [
    "# 本地文件\n",
    "np.save(\"../datasets/my_mnist_tests.npy\", X_new)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:38:16.468359Z",
     "start_time": "2020-06-13T10:38:16.459500Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['flatten_input']"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.input_names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:38:32.032929Z",
     "start_time": "2020-06-13T10:38:32.024256Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['dense_1']"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.output_names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:37:27.319042Z",
     "start_time": "2020-06-13T10:37:27.312784Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'flatten_input'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "input_name = model.input_names[0]\n",
    "input_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:37:29.844629Z",
     "start_time": "2020-06-13T10:37:28.536559Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2020-06-13 18:37:29.540254: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcuda.so.1\n",
      "2020-06-13 18:37:29.542962: E tensorflow/stream_executor/cuda/cuda_driver.cc:313] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected\n",
      "2020-06-13 18:37:29.542999: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: carpediem\n",
      "2020-06-13 18:37:29.543005: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: carpediem\n",
      "2020-06-13 18:37:29.543073: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 440.48.2\n",
      "2020-06-13 18:37:29.543118: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 440.48.2\n",
      "2020-06-13 18:37:29.543123: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 440.48.2\n",
      "2020-06-13 18:37:29.543294: I tensorflow/core/platform/cpu_feature_guard.cc:143] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "2020-06-13 18:37:29.565334: I tensorflow/core/platform/profile_utils/cpu_utils.cc:102] CPU Frequency: 3600000000 Hz\n",
      "2020-06-13 18:37:29.566319: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7fc604000b20 initialized for platform Host (this does not guarantee that XLA will be used). Devices:\n",
      "2020-06-13 18:37:29.566359: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version\n",
      "WARNING:tensorflow:From /home/yangbin7/anaconda3/lib/python3.7/site-packages/tensorflow/python/tools/saved_model_cli.py:443: load (from tensorflow.python.saved_model.loader_impl) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "This function will only be available through the v1 compatibility library as tf.compat.v1.saved_model.loader.load or tf.compat.v1.saved_model.load. There will be a new function for importing SavedModels in Tensorflow 2.0.\n",
      "INFO:tensorflow:Restoring parameters from ../../H/models/my_mnist_model/0001/variables/variables\n",
      "Result for output key dense_1:\n",
      "[[1.1499867e-04 1.5268439e-07 9.8030013e-04 2.7796803e-03 3.7903319e-06\n",
      "  7.7228033e-05 3.9526704e-08 9.9555629e-01 5.3869553e-05 4.3363599e-04]\n",
      " [8.1089587e-04 3.4952860e-05 9.8837006e-01 6.9874134e-03 1.2793694e-07\n",
      "  2.2997544e-04 2.5401313e-03 9.5880859e-10 1.0263891e-03 8.6737614e-08]\n",
      " [4.4491670e-05 9.7029006e-01 9.0702996e-03 2.2668873e-03 4.8802438e-04\n",
      "  2.8743150e-03 2.2734071e-03 8.3535137e-03 4.0411884e-03 2.9781050e-04]]\n"
     ]
    }
   ],
   "source": [
    "# 调用本地模型\n",
    "!saved_model_cli run --dir {model_path} --tag_set serve \\\n",
    "                     --signature_def serving_default    \\\n",
    "                     --inputs {input_name}=../datasets/my_mnist_tests.npy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-08T15:31:19.817294Z",
     "start_time": "2020-06-08T15:31:19.810129Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 1.  , 0.  , 0.  ],\n",
       "       [0.  , 0.  , 0.99, 0.01, 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ],\n",
       "       [0.  , 0.96, 0.01, 0.  , 0.  , 0.  , 0.  , 0.01, 0.01, 0.  ]])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.round([[\n",
    "    1.1739199e-04, 1.1239604e-07, 6.0210604e-04, 2.0804715e-03, 2.5779348e-06,\n",
    "    6.4079795e-05, 2.7411186e-08, 9.9669880e-01, 3.9654213e-05, 3.9471846e-04\n",
    "],\n",
    "          [\n",
    "              1.2294615e-03, 2.9207937e-05, 9.8599273e-01, 9.6755642e-03,\n",
    "              8.8930705e-08, 2.9156188e-04, 1.5831805e-03, 1.1311053e-09,\n",
    "              1.1980456e-03, 1.1113169e-07\n",
    "          ],\n",
    "          [\n",
    "              6.4066830e-05, 9.6359509e-01, 9.0598064e-03, 2.9872139e-03,\n",
    "              5.9552520e-04, 3.7478798e-03, 2.5074568e-03, 1.1462728e-02,\n",
    "              5.5553433e-03, 4.2495009e-04\n",
    "          ]], 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 部署模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:39:19.746956Z",
     "start_time": "2020-06-13T10:39:19.740885Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/home/yangbin7/H/models/my_mnist_model'"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model_path = os.path.abspath('../../H/models/my_mnist_model')\n",
    "model_path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:39:22.618212Z",
     "start_time": "2020-06-13T10:39:21.896075Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3e97864a384d5d2d0661b038824af45f358e38ed37fd9f75b8d8320a32ca02f3\r\n"
     ]
    }
   ],
   "source": [
    "# 运行模型\n",
    "!docker run -it --rm -p 8500:8500 -p 8501:8501 \\\n",
    "        -v \"$model_path:/models/my_mnist_model\" \\\n",
    "        -e MODEL_NAME=my_mnist_model \\\n",
    "        -d tensorflow/serving"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:39:25.416572Z",
     "start_time": "2020-06-13T10:39:25.275520Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                              NAMES\r\n",
      "3e97864a384d        tensorflow/serving   \"/usr/bin/tf_serving…\"   3 seconds ago       Up 2 seconds        0.0.0.0:8500-8501->8500-8501/tcp   upbeat_knuth\r\n"
     ]
    }
   ],
   "source": [
    "!docker ps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## REST API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-08T15:54:53.063547Z",
     "start_time": "2020-06-08T15:54:53.056938Z"
    }
   },
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "input_data_json = json.dumps({\n",
    "    \"signature_name\": \"serving_default\",\n",
    "    \"instances\": X_new.tolist(), # 为什么是这种形式\n",
    "})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-08T15:55:18.786867Z",
     "start_time": "2020-06-08T15:55:18.761992Z"
    }
   },
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "SERVER_URL = 'http://localhost:8501/v1/models/my_mnist_model:predict'\n",
    "response = requests.post(SERVER_URL, data=input_data_json)\n",
    "response.raise_for_status() # raise an exception in case of error\n",
    "response = response.json()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-08T15:55:28.083507Z",
     "start_time": "2020-06-08T15:55:28.077715Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'predictions': [[0.000113945083,\n",
       "   1.51165395e-07,\n",
       "   0.00097856042,\n",
       "   0.00277804374,\n",
       "   3.7648972e-06,\n",
       "   7.63042772e-05,\n",
       "   3.89179782e-08,\n",
       "   0.99556762,\n",
       "   5.23388844e-05,\n",
       "   0.000429277687],\n",
       "  [0.000816865184,\n",
       "   3.53646938e-05,\n",
       "   0.988218,\n",
       "   0.00707711279,\n",
       "   1.28269079e-07,\n",
       "   0.000233427039,\n",
       "   0.0025804257,\n",
       "   9.64154867e-10,\n",
       "   0.00103865331,\n",
       "   8.68936567e-08],\n",
       "  [4.47355778e-05,\n",
       "   0.970272243,\n",
       "   0.00908343308,\n",
       "   0.00227006385,\n",
       "   0.000486535311,\n",
       "   0.00287033687,\n",
       "   0.00227623642,\n",
       "   0.00836951472,\n",
       "   0.00402864302,\n",
       "   0.000298208324]]}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-08T15:55:55.527244Z",
     "start_time": "2020-06-08T15:55:55.521121Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 1.  , 0.  , 0.  ],\n",
       "       [0.  , 0.  , 0.99, 0.01, 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ],\n",
       "       [0.  , 0.97, 0.01, 0.  , 0.  , 0.  , 0.  , 0.01, 0.  , 0.  ]])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_proba = np.array(response[\"predictions\"])\n",
    "y_proba.round(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## gRPC API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-08T16:03:11.748925Z",
     "start_time": "2020-06-08T16:03:11.738760Z"
    }
   },
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'tensorflow_serving_apis'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-35-9569aa8ce901>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mtensorflow_serving_apis\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpredict_pb2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mPredictRequest\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0mrequest\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPredictRequest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodel_name\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mrequest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodel_spec\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msignature_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"serving_default\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'tensorflow_serving_apis'"
     ]
    }
   ],
   "source": [
    "from tensorflow_serving_apis.predict_pb2 import PredictRequest\n",
    "\n",
    "request = PredictRequest()\n",
    "request.model_spec.name = model_name\n",
    "request.model_spec.signature_name = \"serving_default\"\n",
    "input_name = model.input_names[0]\n",
    "request.inputs[input_name].CopyFrom(tf.make_tensor_proto(X_new))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import grpc\n",
    "from tensorflow_serving_apis import prediction_service_pb2_grpc\n",
    "\n",
    "channel = grpc.insecure_channel('localhost:8500')\n",
    "predict_service = prediction_service_pb2_grpc.PredictionServiceStub(channel)\n",
    "response = predict_service.Predict(request, timeout=10.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "output_name = model.output_names[0]\n",
    "outputs_proto = response.outputs[output_name]\n",
    "y_proba = tf.make_ndarray(outputs_proto)\n",
    "y_proba.round(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "output_name = model.output_names[0]\n",
    "outputs_proto = response.outputs[output_name]\n",
    "shape = [dim.size for dim in outputs_proto.tensor_shape.dim]\n",
    "y_proba = np.array(outputs_proto.float_val).reshape(shape)\n",
    "y_proba.round(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:01:39.275631Z",
     "start_time": "2020-06-13T10:01:39.266267Z"
    }
   },
   "outputs": [],
   "source": [
    "class TextCnn(tf.keras.Model):\n",
    "    def __init__(self,\n",
    "                 maxlen,\n",
    "                 max_features,\n",
    "                 class_num,\n",
    "                 embedding_dims,\n",
    "                 embeddings_matrix,\n",
    "                 kernel_sizes=[1, 2, 3, 4, 5],\n",
    "                 last_activation='sigmoid'):  \n",
    "        super(TextCnn, self).__init__()\n",
    "        self.maxlen = maxlen\n",
    "        self.max_features = max_features\n",
    "        self.embedding_dims = embedding_dims\n",
    "        self.kernel_sizes = kernel_sizes\n",
    "        self.class_num = class_num\n",
    "        self.last_activation = last_activation\n",
    "        self.embeddings_matrix = embeddings_matrix\n",
    "        self.embedding = keras.layers.Embedding(\n",
    "            self.max_features,\n",
    "            self.embedding_dims,\n",
    "            weights=[embeddings_matrix],\n",
    "            input_length=self.maxlen)  # 重点：weights预训练的词向量\n",
    "        self.convs = []\n",
    "        self.max_poolings = []\n",
    "        for kernel_size in self.kernel_sizes:\n",
    "            self.convs.append(keras.layers.Conv1D(128, kernel_size))\n",
    "            self.max_poolings.append(keras.layers.GlobalMaxPooling1D())\n",
    "        self.classifier = keras.layers.Dense(self.class_num,\n",
    "                                             activation=self.last_activation)\n",
    "        self.dropout = keras.layers.Dropout(0.15)  #百分之20的神经元不工作\n",
    "        self.norma = keras.layers.LayerNormalization()\n",
    "        self.act = keras.layers.Activation('relu')\n",
    "        self.softmax = keras.layers.Softmax()\n",
    "\n",
    "    def call(self, inputs):\n",
    "        if inputs.get_shape()[1] != self.maxlen:\n",
    "            raise ValueError(\n",
    "                'The maxlen of inputs of TextCNN must be %d, but now is %d' %\n",
    "                (self.maxlen, inputs.get_shape()[1]))\n",
    "        embedding = self.embedding(inputs)\n",
    "        convs = []\n",
    "        for i in range(len(self.kernel_sizes)):\n",
    "            c = self.convs[i](embedding)\n",
    "            c = self.norma(c)\n",
    "            c = self.act(c)\n",
    "            c = self.max_poolings[i](c)\n",
    "            convs.append(c)\n",
    "        x = keras.layers.Concatenate()(convs)\n",
    "        x_1 = self.dropout(x)\n",
    "        output = self.classifier(x_1)\n",
    "        score = self.softmax(output)  #将全链接层的输出，进行softmax运算，得到每个类的概率\n",
    "        return score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:01:41.021883Z",
     "start_time": "2020-06-13T10:01:41.006747Z"
    }
   },
   "outputs": [],
   "source": [
    "from tensorflow import keras\n",
    "word_matrix = tf.random.uniform([30, 50])\n",
    "model = TextCnn(20, 30, 4, 50, word_matrix)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:01:42.153726Z",
     "start_time": "2020-06-13T10:01:42.130170Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 4), dtype=float32, numpy=\n",
       "array([[0.26742765, 0.26718795, 0.27480498, 0.1905794 ],\n",
       "       [0.26635906, 0.2439773 , 0.28277802, 0.20688564],\n",
       "       [0.2495458 , 0.27974066, 0.28159958, 0.18911393]], dtype=float32)>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inputs = np.random.randint(2, 10, (3, 20))\n",
    "model(inputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:01:46.921070Z",
     "start_time": "2020-06-13T10:01:45.713620Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Assets written to: hhhhh/assets\n"
     ]
    }
   ],
   "source": [
    "tf.saved_model.save(model, 'hhhhh')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:01:50.629225Z",
     "start_time": "2020-06-13T10:01:49.401631Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The given SavedModel contains the following tag-sets:\r\n",
      "'serve'\r\n"
     ]
    }
   ],
   "source": [
    "model_path = \"hhhhh/\"\n",
    "!saved_model_cli show --dir {model_path}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T10:01:52.892459Z",
     "start_time": "2020-06-13T10:01:51.243434Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:\n",
      "\n",
      "signature_def['__saved_model_init_op']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['__saved_model_init_op'] tensor_info:\n",
      "        dtype: DT_INVALID\n",
      "        shape: unknown_rank\n",
      "        name: NoOp\n",
      "  Method name is: \n",
      "\n",
      "signature_def['serving_default']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "    inputs['input_1'] tensor_info:\n",
      "        dtype: DT_INT64\n",
      "        shape: (-1, 20)\n",
      "        name: serving_default_input_1:0\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['output_1'] tensor_info:\n",
      "        dtype: DT_FLOAT\n",
      "        shape: (-1, 4)\n",
      "        name: StatefulPartitionedCall:0\n",
      "  Method name is: tensorflow/serving/predict\n",
      "WARNING:tensorflow:From /home/yangbin7/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "\n",
      "Defined Functions:\n",
      "  Function Name: '__call__'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 20), dtype=tf.int64, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "    Option #2\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 20), dtype=tf.int64, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "    Option #3\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 20), dtype=tf.int64, name='input_1')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "    Option #4\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 20), dtype=tf.int64, name='input_1')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "\n",
      "  Function Name: '_default_save_signature'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 20), dtype=tf.int64, name='input_1')\n",
      "\n",
      "  Function Name: 'call_and_return_all_conditional_losses'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 20), dtype=tf.int64, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "    Option #2\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 20), dtype=tf.int64, name='input_1')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: False\n",
      "    Option #3\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          inputs: TensorSpec(shape=(None, 20), dtype=tf.int64, name='inputs')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n",
      "    Option #4\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 20), dtype=tf.int64, name='input_1')\n",
      "        Argument #2\n",
      "          DType: bool\n",
      "          Value: True\n"
     ]
    }
   ],
   "source": [
    "!saved_model_cli show --dir {model_path} --all"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T09:27:41.804998Z",
     "start_time": "2020-06-13T09:27:41.799852Z"
    }
   },
   "outputs": [],
   "source": [
    "reshape = tf.keras.layers.Reshape((-1, 10))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-13T09:27:56.138886Z",
     "start_time": "2020-06-13T09:27:56.132099Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(3, 2, 10), dtype=int64, numpy=\n",
       "array([[[5, 3, 6, 2, 4, 4, 4, 3, 7, 4],\n",
       "        [3, 7, 9, 8, 5, 4, 2, 9, 3, 3]],\n",
       "\n",
       "       [[4, 4, 7, 9, 5, 4, 6, 4, 5, 7],\n",
       "        [5, 3, 2, 6, 8, 5, 9, 8, 8, 5]],\n",
       "\n",
       "       [[7, 3, 6, 7, 3, 3, 8, 7, 5, 6],\n",
       "        [2, 4, 9, 2, 7, 2, 3, 8, 4, 4]]])>"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reshape(inputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T15:54:05.828623Z",
     "start_time": "2020-06-18T15:54:04.955152Z"
    }
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T15:54:34.757548Z",
     "start_time": "2020-06-18T15:54:34.752412Z"
    }
   },
   "outputs": [],
   "source": [
    "class MyModel(tf.keras.Model):\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        self.dense1 = tf.keras.layers.Dense(100, activation='relu')\n",
    "        self.dense2 = tf.keras.layers.Dense(6, activation='softmax')\n",
    "\n",
    "    def call(self, inp):\n",
    "        # 当使用 (inp.shape[0],-1) 模型就无法保存成功\n",
    "        # 当使用 [tf.shape(inp)[0], -1] 成功\n",
    "        x = tf.reshape(inp, [tf.shape(inp)[0], -1])\n",
    "        x = self.dense1(x)\n",
    "        y = self.dense2(x)\n",
    "        return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T15:54:35.994530Z",
     "start_time": "2020-06-18T15:54:35.879009Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(2, 6), dtype=float32, numpy=\n",
       "array([[0.10305609, 0.13621774, 0.13960676, 0.3097873 , 0.26117367,\n",
       "        0.0501584 ],\n",
       "       [0.17174944, 0.14442973, 0.15293509, 0.3334627 , 0.16186215,\n",
       "        0.03556088]], dtype=float32)>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = MyModel()\n",
    "inp = tf.random.uniform([2, 28, 28, 1])\n",
    "model(inp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T15:54:37.483578Z",
     "start_time": "2020-06-18T15:54:37.312322Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /home/yangbin7/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "INFO:tensorflow:Assets written to: hhhh/assets\n"
     ]
    }
   ],
   "source": [
    "tf.saved_model.save(model, 'hhhh')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyModel(tf.keras.Model):\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        self.dense1 = tf.keras.layers.Dense(100, activation='relu')\n",
    "        self.dense2 = tf.keras.layers.Dense(6, activation='softmax')\n",
    "\n",
    "    def call(self, inp):\n",
    "        # 当使用 (inp.shape[0],-1) 模型就无法保存成功\n",
    "        # 当使用 [tf.shape(inp)[0], -1] 成功\n",
    "        x = tf.reshape(inp, [tf.shape(inp)[0], -1])\n",
    "        x = self.dense1(x)\n",
    "        y = self.dense2(x)\n",
    "        return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:03:21.181856Z",
     "start_time": "2020-06-18T17:03:21.173028Z"
    }
   },
   "outputs": [],
   "source": [
    "class MyModel(tf.keras.Model):\n",
    "    def __init__(self, aspect_input, num_class):\n",
    "        super(MyModel, self).__init__()\n",
    "        self.aspect_input = aspect_input\n",
    "        self.num_aspect, self.aspect_len = aspect_input.shape\n",
    "\n",
    "        self.num_class = num_class\n",
    "\n",
    "        self.embed = tf.keras.layers.Embedding(10000, 56)\n",
    "        self.dense1 = tf.keras.layers.Dense(100, activation='relu')\n",
    "        self.dense2 = tf.keras.layers.Dense(num_class, activation='softmax')\n",
    "\n",
    "    def _get_aspect(self):\n",
    "        aspect_embed = self.embed(self.aspect_input)\n",
    "        return aspect_embed\n",
    "\n",
    "    def call(self, inp):  # batch,seq_len\n",
    "        batch = tf.shape(inp)[0]\n",
    "        word_embed = self.embed(inp)  # batch,seq_len,embed_size\n",
    "        word_embed = tf.reduce_sum(word_embed, axis=1)  # batch,embed_size\n",
    "        word_embed = tf.tile(tf.expand_dims(word_embed, axis=1),\n",
    "                             multiples=[1, self.num_aspect, 1])\n",
    "        print(word_embed.shape)\n",
    "        # batch,num_aspect,embed_size\n",
    "\n",
    "        aspect_embed = self._get_aspect()  # num_aspect,aspect_len,embed_size\n",
    "        aspect_embed = tf.reduce_mean(aspect_embed,\n",
    "                                      axis=1)  # num_aspect,embed_size\n",
    "        aspect_embed = tf.tile(tf.expand_dims(aspect_embed, axis=0),\n",
    "                               multiples=[batch, 1, 1])\n",
    "        print(aspect_embed.shape)\n",
    "        # batch,num_aspect, embed_size\n",
    "        \n",
    "        embed = tf.concat([word_embed,aspect_embed], axis=-1)\n",
    "        print(embed.shape)\n",
    "        # batch,num_aspect,2*embed_size\n",
    "        \n",
    "        x = self.dense1(embed)\n",
    "        y = self.dense2(embed)\n",
    "\n",
    "        return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:03:22.099624Z",
     "start_time": "2020-06-18T17:03:22.094000Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:03:22.715265Z",
     "start_time": "2020-06-18T17:03:22.708961Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(7, 4), dtype=int32, numpy=\n",
       "array([[50, 21,  3, 44],\n",
       "       [41, 46,  2, 31],\n",
       "       [77, 29, 62, 52],\n",
       "       [81, 89, 87, 78],\n",
       "       [57, 78, 90,  3],\n",
       "       [25, 16,  3,  1],\n",
       "       [21, 11, 60, 38]], dtype=int32)>"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "aspect = tf.constant(np.random.randint(1, 100, (7, 4)), dtype=tf.int32)\n",
    "aspect                     "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:03:23.227180Z",
     "start_time": "2020-06-18T17:03:23.220985Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(2, 9), dtype=int32, numpy=\n",
       "array([[168, 990, 338, 376, 620, 444, 128, 230, 121],\n",
       "       [ 64, 293,  38,  86, 524, 476, 543, 853, 988]], dtype=int32)>"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inp = tf.constant(np.random.randint(1, 1000, (2, 9)), dtype=tf.int32)\n",
    "inp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:03:24.972898Z",
     "start_time": "2020-06-18T17:03:24.965098Z"
    }
   },
   "outputs": [],
   "source": [
    "my_model = MyModel(aspect, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:03:33.277696Z",
     "start_time": "2020-06-18T17:03:33.268724Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2, 7, 56)\n",
      "(2, 7, 56)\n",
      "(2, 7, 112)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(2, 7, 4), dtype=float32, numpy=\n",
       "array([[[0.2535123 , 0.25352374, 0.24321787, 0.24974607],\n",
       "        [0.2602636 , 0.25252223, 0.24250811, 0.24470611],\n",
       "        [0.2635415 , 0.25121826, 0.24079615, 0.24444407],\n",
       "        [0.25485468, 0.25221926, 0.24111736, 0.25180873],\n",
       "        [0.25300932, 0.24960595, 0.24246114, 0.25492358],\n",
       "        [0.2552147 , 0.2494412 , 0.24522544, 0.25011867],\n",
       "        [0.25443554, 0.2559735 , 0.23960853, 0.2499824 ]],\n",
       "\n",
       "       [[0.25909325, 0.23844846, 0.2584526 , 0.24400571],\n",
       "        [0.26591882, 0.23744014, 0.25762632, 0.23901473],\n",
       "        [0.26925492, 0.2362026 , 0.25579524, 0.23874725],\n",
       "        [0.2604839 , 0.23723859, 0.2562389 , 0.24603862],\n",
       "        [0.25856486, 0.23475061, 0.25763413, 0.24905041],\n",
       "        [0.2607295 , 0.23451546, 0.26048237, 0.24427265],\n",
       "        [0.26012966, 0.24083848, 0.25470805, 0.24432382]]], dtype=float32)>"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_model(inp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:04:02.634954Z",
     "start_time": "2020-06-18T17:04:02.335489Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(None, 7, 56)\n",
      "(None, 7, 56)\n",
      "(None, 7, 112)\n",
      "(None, 7, 56)\n",
      "(None, 7, 56)\n",
      "(None, 7, 112)\n",
      "INFO:tensorflow:Assets written to: hhhh/assets\n"
     ]
    }
   ],
   "source": [
    "tf.saved_model.save(my_model, 'hhhh')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T17:04:56.671937Z",
     "start_time": "2020-06-18T17:04:55.380988Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:\n",
      "\n",
      "signature_def['__saved_model_init_op']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['__saved_model_init_op'] tensor_info:\n",
      "        dtype: DT_INVALID\n",
      "        shape: unknown_rank\n",
      "        name: NoOp\n",
      "  Method name is: \n",
      "\n",
      "signature_def['serving_default']:\n",
      "  The given SavedModel SignatureDef contains the following input(s):\n",
      "    inputs['input_1'] tensor_info:\n",
      "        dtype: DT_INT32\n",
      "        shape: (-1, 9)\n",
      "        name: serving_default_input_1:0\n",
      "  The given SavedModel SignatureDef contains the following output(s):\n",
      "    outputs['output_1'] tensor_info:\n",
      "        dtype: DT_FLOAT\n",
      "        shape: (-1, 7, 4)\n",
      "        name: StatefulPartitionedCall:0\n",
      "  Method name is: tensorflow/serving/predict\n",
      "WARNING:tensorflow:From /home/yangbin7/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "\n",
      "Defined Functions:\n",
      "  Function Name: '__call__'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 9), dtype=tf.int32, name='input_1')\n",
      "\n",
      "  Function Name: '_default_save_signature'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 9), dtype=tf.int32, name='input_1')\n",
      "\n",
      "  Function Name: 'call_and_return_all_conditional_losses'\n",
      "    Option #1\n",
      "      Callable with:\n",
      "        Argument #1\n",
      "          input_1: TensorSpec(shape=(None, 9), dtype=tf.int32, name='input_1')\n"
     ]
    }
   ],
   "source": [
    "!saved_model_cli show --dir 'hhhh' --all"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 不使用 tf.function 时保存没有问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
